package com.zmj.sy.mom.srv.aps.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zmj.sy.mom.srv.aps.bean.dto.feign.Ltk.LtkPushTokenDto;
import com.zmj.sy.mom.srv.aps.bean.entity.lantekpre.LantekPushPackage;
import com.zmj.sy.mom.srv.aps.bean.entity.lantekpre.LantekPushPlan;
import com.zmj.sy.mom.srv.aps.bean.entity.mes.Plate;
import com.zmj.sy.mom.srv.aps.bean.entity.mes.PlatePhase;
import com.zmj.sy.mom.srv.aps.bean.entity.mes.WmsPlatePick;
import com.zmj.sy.mom.srv.aps.bean.entity.mes.WorkDetailTask;
import com.zmj.sy.mom.srv.aps.bean.entity.nest.*;
import com.zmj.sy.mom.srv.aps.bean.entity.order.*;
import com.zmj.sy.mom.srv.aps.bean.entity.resource.DictData;
import com.zmj.sy.mom.srv.aps.bean.entity.resource.DictType;
import com.zmj.sy.mom.srv.aps.bean.entity.resource.LogApi;
import com.zmj.sy.mom.srv.aps.bean.entity.third.*;
import com.zmj.sy.mom.srv.aps.bean.vo.base.*;
import com.zmj.sy.mom.srv.aps.bean.vo.lantek.*;
import com.zmj.sy.mom.srv.aps.bean.vo.nest.*;
import com.zmj.sy.mom.srv.aps.bean.vo.nest.newNest.ReceiveNestPlateReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.nest.release.*;
import com.zmj.sy.mom.srv.aps.bean.vo.nest.workspace.*;
import com.zmj.sy.mom.srv.aps.bean.vo.nestpre.LantekNewPrePlanInfoVo;
import com.zmj.sy.mom.srv.aps.bean.vo.nestpre.LantekNewPrePlanVo;
import com.zmj.sy.mom.srv.aps.bean.vo.nestpre.LantekPrePushPlan;
import com.zmj.sy.mom.srv.aps.bean.vo.nestpre.LantekPrePushReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.plate.PlateListReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.plate.PlateListResVo;
import com.zmj.sy.mom.srv.aps.config.ProjectConfig;
import com.zmj.sy.mom.srv.aps.config.StrategyConfig;
import com.zmj.sy.mom.srv.aps.feign.ApsWmsApiClient;
import com.zmj.sy.mom.srv.aps.feign.LantekProApiClient;
import com.zmj.sy.mom.srv.aps.mapper.*;
import com.zmj.sy.mom.srv.aps.utils.*;
import com.zmj.sy.mom.srv.aps.utils.mybatisplus.WrapperUtil;
import com.zmj.sy.mom.srv.aps.utils.nest.HexagonNestRule;
import com.zmj.sy.mom.srv.aps.utils.nest.LantekNestRule;
import com.zmj.sy.mom.srv.aps.utils.nest.NestRule;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@RequiredArgsConstructor
@Service
public class NestService {

    private final ObjectMapper objectMapper;

    private final StrategyConfig strategyConfig;

    private final OrderMapper orderMapper;

    private final ApsWorkDetailMapper apsWorkDetailMapper;

    private final OrderBomMapper orderBomMapper;

    private final SinoCamPushDrawingMapper sinoCamPushDrawingMapper;

    private final NestSpaceMapper nestSpaceMapper;

    private final NestSpacePartMapper nestSpacePartMapper;

    private final ApsWorkOrderMapper apsWorkOrderMapper;

    private final ProjectConfig projectConfig;

    private final SinoCamPushPlanMapper sinoCamPushPlanMapper;

    private final ApsOrderMapper apsOrderMapper;

    private final LantekPushPlanMapper lantekPushPlanMapper;

    private final NestSpacePlateMapper nestSpacePlateMapper;

    private final ApsWmsApiClient apsWmsApiClient;

    private final LantekProApiClient lantekProApiClient;

    private final HexagonPackagePushMapper hexagonPackagePushMapper;

    private final OrderPhaseMapper orderPhaseMapper;

    private final ImportErpMappingMapper importErpMappingMapper;
    private final SinoCamReceiveNestPlateMapper sinoCamReceiveNestPlateMapper;
    private final SinoCamReceiveNestNestMapper sinoCamReceiveNestNestMapper;

    private final HexagonNestRule hexagonNestRule;
    private final LantekPushPackageMapper lantekPushPackageMapper;
    private final DictTypeMapper dictTypeMapper;
    private final DictDataMapper dictDataMapper;
    private final LantekNestRule lantekNestRule;
    private final NestReceiveNestMapper nestReceiveNestMapper;
    private final NestReceivePartMapper nestReceivePartMapper;
    private final NestReceivePlateMapper nestReceivePlateMapper;
    private final NestReceiveExcessMapper nestReceiveExcessMapper;
    private final NestReceiveMoveMapper nestReceiveMoveMapper;
    private final PlateMapper plateMapper;
    private final PlatePhaseMapper platePhaseMapper;
    private final WmsPlatePickMapper wmsPlatePickMapper;
    private final WorkDetailTaskMapper workDetailTaskMapper;

    @Transactional(rollbackFor = Exception.class)
    public void workspaceAdd(NestWorkspaceAddReqVo reqVo) {
        NestSpace nestSpace = MkBeanUtils.copyProperties(reqVo, NestSpace.class);
        String userCode = SySecurityUtils.getUserCode();
        nestSpace.setSpaceCode(userCode + "_" + reqVo.getGroupCode() + "_" + reqVo.getTexture() + "_" + reqVo.getThickness());
        nestSpace.setStatus(1);
        nestSpaceMapper.insert(nestSpace);
    }

    @Transactional
    public List<NestWorkspaceListResVo> workspaceList(NestWorkspaceListReqVo reqVo) {
        List<NestSpace> list = nestSpaceMapper.lambdaQuery()
                .eq(NestSpace::getCreateUsername, reqVo.getUserCode())
                .like(StringUtils.hasText(reqVo.getSpaceCode()), NestSpace::getSpaceCode, reqVo.getSpaceCode())
                .like(StringUtils.hasText(reqVo.getGroupCode()), NestSpace::getGroupCode, reqVo.getGroupCode())
                .eq(reqVo.getStatus() != null, NestSpace::getStatus, reqVo.getStatus())
//                .ne(NestSpace::getStatus, 3)
                .orderByDesc(NestSpace::getCreateDateTime)
                .list();
        if (CollUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        List<NestSpacePart> nestSpacePartList = nestSpacePartMapper.lambdaQuery()
                .in(NestSpacePart::getSpaceId, list.stream().map(NestSpace::getId).collect(Collectors.toList()))
                .list();
        Map<Integer, List<NestSpacePart>> nestSpacePartMap = nestSpacePartList.stream().collect(Collectors.groupingBy(NestSpacePart::getSpaceId));
        List<NestSpacePlate> nestSpacePlateList = nestSpacePlateMapper.lambdaQuery()
                .in(NestSpacePlate::getSpaceId, list.stream().map(NestSpace::getId).collect(Collectors.toList()))
                .list();
        Map<Integer, List<NestSpacePlate>> nestSpacePlateMap = nestSpacePlateList.stream().collect(Collectors.groupingBy(NestSpacePlate::getSpaceId));
        return list.stream()
                .map(e->{
                    List<NestSpacePart> spacePartList = nestSpacePartMap.get(e.getId());
                    List<NestSpacePlate> nestSpacePlates = nestSpacePlateMap.get(e.getId());
                    NestWorkspaceListResVo vo = MkBeanUtils.copyProperties(e, NestWorkspaceListResVo.class);
                    vo.setPlateCount(CollUtil.isNotEmpty(nestSpacePlates) ? nestSpacePlates.size() : 0);
                    vo.setPartCount(CollUtil.isNotEmpty(spacePartList) ? spacePartList.size() : 0);
                    return vo;
                })
                .collect(Collectors.toList());

    }

    @Transactional(readOnly = true)
    public List<NestWorkspaceAllResVo> workspaceAll() {
        List<NestSpace> list = nestSpaceMapper.lambdaQuery()
                .orderByDesc(NestSpace::getSpaceCode)
                .list();
        List<NestSpacePart> nestSpacePartList = nestSpacePartMapper.selectBatchIds(list.stream().map(NestSpace::getId).collect(Collectors.toList()));
        Map<Integer, List<NestSpacePart>> nestSpacePartMap = nestSpacePartList.stream().collect(Collectors.groupingBy(NestSpacePart::getSpaceId));
        List<NestSpacePlate> nestSpacePlateList = nestSpacePlateMapper.selectBatchIds(list.stream().map(NestSpace::getId).collect(Collectors.toList()));
        Map<Integer, List<NestSpacePlate>> nestSpacePlateMap = nestSpacePlateList.stream().collect(Collectors.groupingBy(NestSpacePlate::getSpaceId));
        return list.stream()
                .map(e->{
                    List<NestSpacePart> spacePartList = nestSpacePartMap.get(e.getId());
                    List<NestSpacePlate> nestSpacePlates = nestSpacePlateMap.get(e.getId());
                    NestWorkspaceAllResVo vo = MkBeanUtils.copyProperties(e, NestWorkspaceAllResVo.class);
                    vo.setPlateCount(CollUtil.isNotEmpty(nestSpacePlates) ? nestSpacePlates.size() : 0);
                    vo.setPartCount(CollUtil.isNotEmpty(spacePartList) ? spacePartList.size() : 0);
                    return vo;
                })
                .collect(Collectors.toList());

    }

    public void workspaceClose(BaseIdReqVo reqVo) {

        NestSpace nestSpace = nestSpaceMapper.selectById(reqVo.getId());

        if (StringUtils.hasText(nestSpace.getLantekCode())) {
            throw SyExceptionUtils.e("当前作业区不支持关闭。");
        }

        nestSpacePartMapper.lambdaUpdate()
                .eq(NestSpacePart::getSpaceId, reqVo.getId())
                .set(NestSpacePart::getStatus, 3)
                .update();

        nestSpacePlateMapper.lambdaUpdate()
                .eq(NestSpacePlate::getSpaceId, reqVo.getId())
                .set(NestSpacePlate::getStatus, 3)
                .update();

        nestSpaceMapper.lambdaUpdate()
                .eq(NestSpace::getId, reqVo.getId())
                .set(NestSpace::getStatus, 3)
                .update();

    }

    public void workspaceFinish(BaseIdReqVo reqVo) {
        NestSpace nestSpace = nestSpaceMapper.selectById(reqVo.getId());
        List<NestSpacePart> spacePartList = nestSpacePartMapper.lambdaQuery().eq(NestSpacePart::getSpaceId, reqVo.getId()).eq(NestSpacePart::getStatus, 2).list();
        List<NestSpacePlate> spacePlateList = nestSpacePlateMapper.lambdaQuery().eq(NestSpacePlate::getSpaceId, reqVo.getId()).eq(NestSpacePlate::getStatus, 2).list();

        if (CollUtil.isNotEmpty(spacePartList)) {
            List<Integer> pushPlanIds = spacePartList.stream().map(NestSpacePart::getPartPlanId).collect(Collectors.toList());
            List<SinoCamPushPlan> pushPlanList = sinoCamPushPlanMapper.selectBatchIds(pushPlanIds);
            List<NestReleasePartInfoVo> orders = pushPlanList.stream().map(e -> {
                NestReleasePartInfoVo partInfo = new NestReleasePartInfoVo();
                partInfo.setPlanId(e.getNestPlanId());
                return partInfo;
            }).collect(Collectors.toList());

            NestReleasePartReqVo partRelease = new NestReleasePartReqVo();
            partRelease.setJobRef(nestSpace.getLantekCode());
            partRelease.setOrders(orders);
            partRelease.setUsername("TEST01");
            NestLanPaReleaseResVo proPart = lantekProApiClient.release(partRelease, LtkPushTokenDto.TOKEN);

            if (proPart.getCode() == 200) {
                nestSpacePartMapper.lambdaUpdate().in(NestSpacePart::getId, spacePartList.stream().map(NestSpacePart::getId).collect(Collectors.toList())).set(NestSpacePart::getModifyDateTime, LocalDateTime.now()).set(NestSpacePart::getStatus, 4).update();
            } else {
                throw SyExceptionUtils.e("零件释放失败：{}", proPart.getMessage());
            }
        }

        if (CollUtil.isNotEmpty(spacePlateList)) {
            List<String> prdRefs = spacePlateList.stream().map(NestSpacePlate::getPlateCode).collect(Collectors.toList());
            NestReleasePlateReqVo plateRelease = new NestReleasePlateReqVo();
            plateRelease.setJobRef(nestSpace.getLantekCode());
            plateRelease.setPrdRefs(prdRefs);
            NestLanPlReleaseResVo proPlate = lantekProApiClient.releaseAPSIntegratedInventory(plateRelease, LtkPushTokenDto.TOKEN);
            if (proPlate.getCode() == 200) {
                nestSpacePlateMapper.lambdaUpdate().in(NestSpacePlate::getId, spacePlateList.stream().map(NestSpacePlate::getId).collect(Collectors.toList())).set(NestSpacePlate::getModifyDateTime, LocalDateTime.now()).set(NestSpacePlate::getStatus, 4).update();

                LantekLockStockReqVo plateUnlockVo = new LantekLockStockReqVo();
                plateUnlockVo.setPlateList(prdRefs);
                apsWmsApiClient.pushLanUnlock(plateUnlockVo);
            } else {
                throw SyExceptionUtils.e("钢板释放失败：{}", proPlate.getMessage());
            }
        }

        nestSpaceMapper.lambdaUpdate().eq(NestSpace::getId, nestSpace.getId()).set(NestSpace::getStatus, 4).update();
    }

    public void workspaceCancel(BaseIdReqVo reqVo) {
    }

    public void workspacePush(BaseIdReqVo reqVo) {
        NestSpace nestSpace = nestSpaceMapper.selectById(reqVo.getId());
        String lantekCode = nestSpace.getLantekCode();
        if (StringUtils.hasText(lantekCode)) {
            LantekProOpenReqVo req = new LantekProOpenReqVo();
            req.setJobRef(lantekCode);
            // req.setUsername("Powersync");
            req.setUsername(nestSpace.getCreateUsername());
            lantekProApiClient.openNesting(req, LtkPushTokenDto.TOKEN);
        } else {
            List<NestSpacePart> spacePartList = nestSpacePartMapper.lambdaQuery().eq(NestSpacePart::getSpaceId, reqVo.getId()).eq(NestSpacePart::getStatus, 1).list();

            NestRule nestRule = strategyConfig.getNestRule(NestRule.LANTEK);
            nestRule.planPush(spacePartList.stream().map(NestSpacePart::getPartPlanId).collect(Collectors.toList()), null, null);

            List<NestSpacePlate> spacePlateList = nestSpacePlateMapper.lambdaQuery().eq(NestSpacePlate::getSpaceId, reqVo.getId()).eq(NestSpacePlate::getStatus, 1).list();
            nestRule.platesPush(reqVo.getId(), spacePlateList.stream().map(NestSpacePlate::getPlateCode).collect(Collectors.toList()));
        }

    }

    public void workspacePushPlan(BaseIdReqVo reqVo) {
        NestRule nestRule = strategyConfig.getNestRule(NestRule.LANTEK);
        List<NestSpacePart> spacePartList = nestSpacePartMapper.lambdaQuery().eq(NestSpacePart::getSpaceId, reqVo.getId()).eq(NestSpacePart::getStatus, 1).list();
        nestRule.planPush(spacePartList.stream().map(NestSpacePart::getPartPlanId).collect(Collectors.toList()), null, null);
    }

    public void workspacePushPlate(BaseIdReqVo reqVo) {
        NestRule nestRule = strategyConfig.getNestRule(NestRule.LANTEK);
        List<NestSpacePlate> spacePlateList = nestSpacePlateMapper.lambdaQuery().eq(NestSpacePlate::getSpaceId, reqVo.getId()).eq(NestSpacePlate::getStatus, 1).list();
        nestRule.platesPush(reqVo.getId(), spacePlateList.stream().map(NestSpacePlate::getPlateCode).collect(Collectors.toList()));
    }

    @Transactional(readOnly = true)
    public List<NestPartBindListResVo> partBindList(NestPartBindReqVo reqVo) {
        String userCode = SySecurityUtils.getUserCode();
//        List<NestSpacePart> partList = nestSpacePartMapper.lambdaQuery()
//                .eq(NestSpacePart::getSpaceId, reqVo.getId())
//                .eq(NestSpacePart::getCreateUsername, userCode)
//                .list();
        QueryWrapper<NestSpacePart> qw = new QueryWrapper<>();
        qw.like(StringUtils.hasText(reqVo.getPlmId()), "pp.part_id", reqVo.getPlmId());
        qw.like(StringUtils.hasText(reqVo.getPartName()), "pp.part_name", reqVo.getPartName());
        qw.eq(StringUtils.hasText(reqVo.getTexture()), "pp.replace_texture", reqVo.getTexture());
        qw.eq(reqVo.getThickness() != null, "pp.replace_thickness", reqVo.getThickness());
        qw.eq("spa.space_id", reqVo.getId());
        qw.eq("spa.create_username", userCode);
        qw.ne("spa.total_count", 0);
        return nestSpacePartMapper.partBindList(qw);

//        return partList.stream()
//                .map(e->MkBeanUtils.copyProperties(e, NestPartBindListResVo.class))
//                .collect(Collectors.toList());
    }


    public void pushPrePartAdd(LantekPrePushReqVo reqVo) {

        List<Integer> orderIds = reqVo.getOrderIds();
        String pushType = reqVo.getPushType();

        if (CollUtil.isEmpty(orderIds)) {
            throw SyExceptionUtils.e("选择订单列表为空。");
        }

        if (!StringUtils.hasText(pushType)) {
            pushType = NestRule.LANTEK_PRE;
        }

        NestRule nestRule = strategyConfig.getNestRule(pushType);

        List<OrderBom> orderBomList = orderBomMapper.lambdaQuery().in(OrderBom::getOrderId, orderIds).eq(OrderBom::getMaterType, "Platepart").list();
        nestRule.partAdd(orderBomList);

    }

    public void pushPrePartPush() {
        String pushType = NestRule.LANTEK_PRE;
        NestRule nestRule = strategyConfig.getNestRule(pushType);
        nestRule.partPush();
    }

    public void pushPrePlanAdd(LantekPrePushReqVo reqVo) {

        List<Integer> orderIds = reqVo.getOrderIds();
        String pushType = reqVo.getPushType();

        if (CollUtil.isEmpty(orderIds)) {
            throw SyExceptionUtils.e("选择订单列表为空。");
        }

        if (!StringUtils.hasText(pushType)) {
            pushType = NestRule.LANTEK_PRE;
        }

        List<String> qgPhaseList = new ArrayList<>();
        qgPhaseList.add("JG");
        qgPhaseList.add("HG");

        NestRule nestRule = strategyConfig.getNestRule(pushType);

        for (Integer orderId : orderIds) {
            // 获取所有需要切割的零件
            List<ApsWorkDetail> apsWorkDetailList = apsWorkDetailMapper.lambdaQuery().eq(ApsWorkDetail::getOrderId, orderId).eq(ApsWorkDetail::getStatus, 2).eq(ApsWorkDetail::getType, 2).in(ApsWorkDetail::getPhaseCode, qgPhaseList).list();

            if (CollUtil.isEmpty(apsWorkDetailList)) {
                throw SyExceptionUtils.e("未查询到需要套料的零件信息");
            }

            Order order = orderMapper.selectById(orderId);

            // 状态 6 未套料，7 已至少推送过一次套料
            if (order.getOrderStatus() < 6) {
                throw SyExceptionUtils.e("订单状态不正确，无法套料");
            } else if (order.getOrderStatus() == 6 || order.getOrderStatus() == 7) {
                nestRule.planAdd(apsWorkDetailList, null, null);
            } else {
                throw SyExceptionUtils.e("已套料，无法再次套料");
            }
        }

    }

    public BaseListResVo<LantekPushSelectListVo> pushSelect(BaseIdReqVo reqVo) {

        List<LantekPushSelectListVo> list = new ArrayList<>();
        List<ApsOrder> apsOrders = apsOrderMapper.lambdaQuery().eq(ApsOrder::getOrderId, reqVo.getId()).list();
        for (ApsOrder apsOrder : apsOrders) {
            LantekPushSelectListVo vo = new LantekPushSelectListVo();
            vo.setId(apsOrder.getId());
            vo.setConstructNo(apsOrder.getConstructNo());
            vo.setCustomerName(apsOrder.getCustomerName());
            vo.setMaterCode(apsOrder.getMaterCode());
            vo.setSeq(apsOrder.getSeq());
            vo.setDeliveryDate(apsOrder.getDeliveryDate());
            if (apsOrder.getOrderStatus() == 6) {
                vo.setStatus(0);
            } else {
                vo.setStatus(1);
            }
            list.add(vo);
        }
        return BaseListResVo.of(list, LantekPushSelectListVo.class);
    }

    public void pushPrePlanPush(LantekPrePushPlan reqVo) {
        String pushType = NestRule.LANTEK_PRE;
        NestRule nestRule = strategyConfig.getNestRule(pushType);

        List<LantekPushPlan> list = lantekPushPlanMapper.lambdaQuery().in(LantekPushPlan::getOrderId, reqVo.getOrderIds()).in(LantekPushPlan::getApsOrderId, reqVo.getApsOrderIds()).list();
        nestRule.planPush(list.stream().map(LantekPushPlan::getId).collect(Collectors.toList()), null, null);
    }

    @Transactional
    public void pushPrePlanNew(LantekNewPrePlanVo reqVo) {
        if (CollUtil.isEmpty(reqVo.getInfoVoLIst())) {
            throw SyExceptionUtils.e("未选中订单！");
        }

        String pushType = NestRule.LANTEK_PRE;
        NestRule nestRule = strategyConfig.getNestRule(pushType);

        String timeSplit = TimeSplitUtils.nestPreName();
        String userCode = SySecurityUtils.getUserCode();
        String productCode = timeSplit + "-" + userCode;

        List<LantekNewPrePlanInfoVo> infoVoList = reqVo.getInfoVoLIst();
        for (LantekNewPrePlanInfoVo vo : infoVoList) {
            LantekPushPackage p = new LantekPushPackage();
            p.setOrderId(vo.getId());
            p.setPlmId(vo.getPlmId());
            p.setMaterName(vo.getMaterName());
            p.setOrderCount(vo.getCount());
            p.setPreNestCode(productCode);
            lantekPushPackageMapper.insert(p);
        }
        reqVo.setPreNestCode(productCode);

        List<Integer> orderIdList = reqVo.getInfoVoLIst().stream().map(LantekNewPrePlanInfoVo::getId).collect(Collectors.toList());
        List<OrderBom> orderBomList = orderBomMapper.lambdaQuery().in(OrderBom::getOrderId, orderIdList).eq(OrderBom::getMaterType, "Platepart").list();
        nestRule.planAdd(null, orderBomList, reqVo);

        List<LantekPushPlan> pushPlanList = lantekPushPlanMapper.lambdaQuery().eq(LantekPushPlan::getProductId, productCode).list();
        nestRule.planPush(pushPlanList.stream().map(LantekPushPlan::getId).collect(Collectors.toList()), null, null);
    }

    public void receiveNestPre(String body) {

        String pushType = NestRule.LANTEK_PRE;
        NestRule nestRule = strategyConfig.getNestRule(pushType);

        nestRule.nestReceive(body);

    }

    public void receiveNest(String body) {

        String pushType = NestRule.LANTEK;
        NestRule nestRule = strategyConfig.getNestRule(pushType);

        nestRule.nestReceive(body);

    }

    public void receiveNestHexagon(String body) {

        String pushType = NestRule.HEXAGON;
        NestRule nestRule = strategyConfig.getNestRule(pushType);

        nestRule.nestReceive(body);

    }

    @Transactional(readOnly = true)
    public BasePageResVo<NestPartUnbindListResVo> partUnbindList(NestPartUnbindListReqVo reqVo) {

        QueryWrapper<ApsWorkOrder> query = Wrappers.query();
        Map<String, String> compareType = reqVo.getCompareType();
        //添加查询条件
        WrapperUtil.fixWrapper(query, StringUtils.hasText(reqVo.getSerialCode()), "o.serial_code", compareType.get("serialCode"), reqVo.getSerialCode());
        WrapperUtil.fixWrapper(query, StringUtils.hasText(reqVo.getCustomerName()), "o.customer_name", compareType.get("customerName"), reqVo.getCustomerName());
        WrapperUtil.fixWrapper(query, StringUtils.hasText(reqVo.getPkgCode()), "spp.processing_no", compareType.get("pkgCode"), reqVo.getPkgCode());
        WrapperUtil.fixWrapper(query, StringUtils.hasText(reqVo.getPlmId()), "spp.part_id", compareType.get("plmId"), reqVo.getPlmId());
        WrapperUtil.fixWrapper(query, StringUtils.hasText(reqVo.getMaterName()), "spp.part_name", compareType.get("materName"), reqVo.getMaterName());
        WrapperUtil.fixWrapper(query, StringUtils.hasText(reqVo.getSpec()), "spp.replace_texture", compareType.get("spec"), reqVo.getSpec());
        WrapperUtil.fixWrapper(query, ObjectUtils.isNotEmpty(reqVo.getThickness()), "spp.replace_thickness", compareType.get("thickness"), reqVo.getThickness());
        WrapperUtil.fixWrapper(query, ObjectUtils.isNotEmpty(reqVo.getLength()), "op.length", compareType.get("length"), reqVo.getLength());
        WrapperUtil.fixWrapper(query, ObjectUtils.isNotEmpty(reqVo.getWidth()), "op.width", compareType.get("width"), reqVo.getWidth());
        WrapperUtil.fixWrapper(query, ObjectUtils.isNotEmpty(reqVo.getOrderCount()), "spp.plan_amount", compareType.get("orderCount"), reqVo.getOrderCount());
        WrapperUtil.fixWrapper(query, ObjectUtils.isNotEmpty(reqVo.getNestCount()), "spp.plan_finish_amount", compareType.get("nestCount"), reqVo.getNestCount());
        WrapperUtil.fixWrapper(query, ObjectUtils.isNotEmpty(reqVo.getParentMaterCode()), "spp.component_id", compareType.get("parentMaterCode"), reqVo.getParentMaterCode());
        WrapperUtil.fixWrapper(query, ObjectUtils.isNotEmpty(reqVo.getProductCode()), "spp.product_id", compareType.get("productCode"), reqVo.getParentMaterCode());
        WrapperUtil.fixWrapper(query, ObjectUtils.isNotEmpty(reqVo.getGroupCode()), "awd.group_code", compareType.get("groupCode"), reqVo.getGroupCode());

        if (reqVo.getDrawingReady() != null) {
            if (reqVo.getDrawingReady().equals(1)) {
                query.isNull("awd.drawing_path");
            } else if (reqVo.getDrawingReady().equals(2)) {
                query.isNotNull("awd.drawing_path");
            } else {
                throw SyExceptionUtils.e("未知的绘图状态");
            }
        }

        query.in("o.order_type", 1, 3, 4);
        if (StringUtils.hasText(reqVo.getSort())) {
            reqVo.setSort(reqVo.getSort().replace("planStartDateTime", "spp.need_date"));
            reqVo.setSort(reqVo.getSort().replace("planEndDateTime", "spp.need_date"));
            if (StringUtils.hasText(reqVo.getOrder()) && reqVo.getOrder().trim().equals("desc")) {
                query.orderByDesc(reqVo.getSort());
            } else {
                query.orderByAsc(reqVo.getSort());
            }
        }

        query.eq("spp.deleted", 0);
        query.eq("spd.deleted", 0);
        query.eq("awd.deleted", 0);
        query.eq("op.deleted", 0);
        query.eq("o.deleted", 0);
        query.eq("spp.push_type", 2);
        query.apply("spp.plan_finish_amount < spp.plan_amount");

        Page<NestPartUnbindListResVo> page = apsWorkOrderMapper.productionOrderPost2(query, reqVo.toPage());
        for (NestPartUnbindListResVo record : page.getRecords()) {
            record.setRemainingCount(record.getOrderCount().subtract(record.getNestCount()));
            if (StringUtils.hasText(record.getFilePath())) {
                record.setDrawingReady(2);
            } else {
                record.setDrawingReady(1);
            }

            LocalDateTime planStartDateTime = record.getPlanStartDateTime();
            record.setPlanStartDateTime(planStartDateTime.minusHours(13));
            if (StringUtils.hasText(record.getPngUrl())) {
                record.setPngUrl(String.format(projectConfig.getUrlPre(), record.getPlmId() + ".png", record.getPngUrl()));
            }
        }
        return new BasePageResVo<>(page.getTotal(), page.getRecords());
    }

    @Transactional(readOnly = true)
    public BasePageResVo<NestProPushListPlanResVo> proPushPlanList(NestProPushListPlanReqVo reqVo) {
        if(reqVo.getOrderId() == null){
            return BasePageResVo.empty();
        }

        // 使用卓畅套料库表
        QueryWrapper<SinoCamPushPlan> qw = Wrappers.query();
        qw.eq("p.order_id", reqVo.getOrderId());
        if (StringUtils.hasText(reqVo.getPackageCode())) {
            qw.like("p.processing_no", reqVo.getPackageCode());
        }
        if (StringUtils.hasText(reqVo.getAssPartName())) {
            qw.like("p.component_name", reqVo.getAssPartName());
        }
        if (StringUtils.hasText(reqVo.getAssPartCode())) {
            qw.like("p.component_id", reqVo.getAssPartCode());
        }
        if (StringUtils.hasText(reqVo.getPartCode())) {
            qw.like("p.part_id", reqVo.getPartCode());
        }
        if (StringUtils.hasText(reqVo.getPartName())) {
            qw.like("p.part_name", reqVo.getPartName());
        }
        if (StringUtils.hasText(reqVo.getTexture())) {
            qw.like("p.replace_texture", reqVo.getTexture());
        }
        if (reqVo.getThickness() != null) {
            qw.eq("p.replace_thickness", reqVo.getThickness());
        }
        if (reqVo.getPushType() != null) {
            qw.eq("p.push_type", reqVo.getPushType());
        }
        if (StringUtils.hasText(reqVo.getWorkChain())) {
            qw.like("awo.work_chain", reqVo.getWorkChain());
        }
        if (StringUtils.hasText(reqVo.getGroupCode())) {
            qw.like("awd.group_code", reqVo.getGroupCode());
        }
        if (StringUtils.hasText(reqVo.getMesOrderCode())) {
            qw.like("p.mes_order_code", reqVo.getMesOrderCode());
        }
        if (reqVo.getStatus() != null) {
            qw.eq("p.status", reqVo.getStatus());
        }

        Map<String, String> compareType = new HashMap<>();
        compareType.put("quantity", "p.plan_amount");
        compareType.put("needDate", "p.need_date");
        if(StringUtils.hasText(reqVo.getSort())){
            qw.orderBy(StringUtils.hasText(reqVo.getSort()),!"desc".equals(reqVo.getOrder()), compareType.get(reqVo.getSort()));
        } else {
            qw.orderByDesc("p.`status`");
        }

        qw.orderByAsc("p.processing_no");
        Page<NestProPushListPlanResVo> orderPushStatusResVoPage = sinoCamPushPlanMapper.pushStatusSelect2(reqVo.toPage(), qw);

        List<SinoCamPushDrawing> drawList = sinoCamPushDrawingMapper.lambdaQuery()
                .in(SinoCamPushDrawing::getUniMaterCode, orderPushStatusResVoPage.getRecords().stream().map(NestProPushListPlanResVo::getUniCode).collect(Collectors.toList()))
                .eq(SinoCamPushDrawing::getStatus, 2)
                .eq(SinoCamPushDrawing::getDrawStatus, 2)
                .list();
        if (CollUtil.isNotEmpty(drawList)) {
            Map<String, SinoCamPushDrawing> drawMap = drawList.stream().collect(Collectors.toMap(SinoCamPushDrawing::getUniMaterCode, Function.identity()));
            for (NestProPushListPlanResVo vo : orderPushStatusResVoPage.getRecords()) {
                if (drawMap.containsKey(vo.getUniCode())) {
                    SinoCamPushDrawing d = drawMap.get(vo.getUniCode());
                    vo.setStatus(d.getStatus());
                    vo.setRemark(d.getErrorMsg());
                }
                vo.setThickness(vo.getThickness().setScale(0, RoundingMode.HALF_UP));
            }
        }
        return BasePageResVo.of(orderPushStatusResVoPage, NestProPushListPlanResVo.class);
    }

    @Transactional(rollbackFor = Exception.class)
    public void partIn(NestPartInReqVo reqVo) {
        NestSpace nestSpace = nestSpaceMapper.selectById(reqVo.getSpaceId());
        if (nestSpace == null) {
            throw SyExceptionUtils.e("空间不存在");
        }
        if (nestSpace.getStatus() != 2 && nestSpace.getStatus() != 1) {
            throw SyExceptionUtils.e("状态不正确");
        }

//        SinoCamPushPlan pushPlan = sinoCamPushPlanMapper.selectById(reqVo.getPartPlanId());
        List<SinoCamPushPlan> pushPlanList = sinoCamPushPlanMapper.lambdaQuery().in(SinoCamPushPlan::getNestPlanId, reqVo.getPartPlanId()).list();

        if (CollUtil.isEmpty(pushPlanList)) {
            throw SyExceptionUtils.e("套料计划不存在");
        }

        Map<String, SinoCamPushPlan> pushPlanMap = pushPlanList.stream().collect(Collectors.toMap(SinoCamPushPlan::getNestPlanId, Function.identity()));

        List<Integer> ids = new ArrayList<>();

        for (Integer i : reqVo.getPartPlanId()) {
            SinoCamPushPlan pushPlan = pushPlanMap.get(i.toString());
            if (pushPlan == null) {
                throw SyExceptionUtils.e("套料计划不存在：{}", i);
            }
            if(pushPlan.getPlanFinishAmount().equals(pushPlan.getPlanAmount())){
                throw SyExceptionUtils.e("套料计划已完成");
            }
            Integer count = nestSpacePartMapper.lambdaQuery()
                    .eq(NestSpacePart::getPartPlanId, pushPlan.getId())
                    .in(NestSpacePart::getStatus, 1, 2)
                    .count();
            if (count > 0) {
                throw SyExceptionUtils.e("该零件正在被套料中");
            }
            if (!nestSpace.getThickness().equals(String.valueOf(pushPlan.getReplaceThickness().intValue()))) {
                throw SyExceptionUtils.e("厚度不匹配");
            }
            NestSpacePart nestSpacePart = new NestSpacePart();
            nestSpacePart.setPartPlanId(pushPlan.getId());
            nestSpacePart.setSpaceId(reqVo.getSpaceId());
            nestSpacePart.setTotalCount(pushPlan.getPlanAmount().intValue() - pushPlan.getPlanFinishAmount().intValue());
            nestSpacePart.setFinishCount(0);
            nestSpacePart.setStatus(1);
            nestSpacePartMapper.insert(nestSpacePart);
            ids.add(pushPlan.getId());
        }

        if (StringUtils.hasText(nestSpace.getLantekCode())) {
            NestRule nestRule = strategyConfig.getNestRule(NestRule.LANTEK);
            nestRule.planPush(ids, null, null);
        }

    }

    @Transactional(rollbackFor = Exception.class)
    public void partOut(BaseIdReqVo reqVo) {
        NestSpacePart nestSpacePart = nestSpacePartMapper.selectById(reqVo.getId());
        if (nestSpacePart == null) {
            throw SyExceptionUtils.e("零件不存在");
        }

        if (nestSpacePart.getStatus() != 1) {
            throw SyExceptionUtils.e("状态异常，零件不支持移除！");
        }

        nestSpacePartMapper.deleteHardById(reqVo.getId());

    }

    public BaseListResVo<PlateListResVo> plateBindList(BaseIdReqVo reqVo) {
        List<NestSpacePlate> spacePlateList = nestSpacePlateMapper.lambdaQuery().eq(NestSpacePlate::getSpaceId, reqVo.getId()).ne(NestSpacePlate::getStatus, 3).list();
        if (CollUtil.isEmpty(spacePlateList)) {
            return BaseListResVo.empty();
        }
        Map<String, NestSpacePlate> spacePlateMap = spacePlateList.stream().collect(Collectors.toMap(NestSpacePlate::getPlateCode, Function.identity()));
        List<String> collect = spacePlateList.stream().map(NestSpacePlate::getPlateCode).collect(Collectors.toList());
        PlateListReqVo vo = new PlateListReqVo();
        vo.setPlateCodes(collect);
        vo.setPlateStock(1);
        Result<Page<PlateListResVo>> pageResult = apsWmsApiClient.plateList(vo);
        Page<PlateListResVo> data = pageResult.getData();
        List<PlateListResVo> records = data.getRecords();
        if (CollUtil.isEmpty(spacePlateList)) {
            return BaseListResVo.of(new ArrayList<>(), PlateListResVo.class);
        }
        for (PlateListResVo r : records) {
            NestSpacePlate nestSpacePlate = spacePlateMap.get(r.getPlateId());
            r.setPlanStatus(nestSpacePlate.getStatus());
            r.setId(nestSpacePlate.getId());
        }
        return BaseListResVo.of(records, PlateListResVo.class);
    }

    public BasePageResVo<PlateListResVo> plateUnbindList(PlateListReqVo reqVo) {
        Result<Page<PlateListResVo>> pageResult = apsWmsApiClient.plateList(reqVo);
        Page<PlateListResVo> data = pageResult.getData();
        return BasePageResVo.of(data, PlateListResVo.class);
    }

    public void plateIn(NestPlateInReqVo reqVo) {
        NestSpace nestSpace = nestSpaceMapper.selectById(reqVo.getSpaceId());
        if (nestSpace == null) {
            throw SyExceptionUtils.e("空间不存在");
        }
        if (nestSpace.getStatus() != 2 && nestSpace.getStatus() != 1) {
            throw SyExceptionUtils.e("状态不正确");
        }
        if (CollUtil.isEmpty(reqVo.getPlateList())) {
            throw SyExceptionUtils.e("未选中钢板！");
        }

        List<NestSpacePlate> spacePlateList = nestSpacePlateMapper.lambdaQuery().in(NestSpacePlate::getPlateCode, reqVo.getPlateList()).in(NestSpacePlate::getStatus, 1, 2).list();
        if (CollUtil.isNotEmpty(spacePlateList)) {
            throw SyExceptionUtils.e("存在已移入的钢板！");
        }
        List<NestSpacePlate> finishPlateList = nestSpacePlateMapper.lambdaQuery().in(NestSpacePlate::getPlateCode, reqVo.getPlateList()).eq(NestSpacePlate::getStatus, 4).eq(NestSpacePlate::getCount, 1).list();
        if (CollUtil.isNotEmpty(finishPlateList)) {
            throw SyExceptionUtils.e("存在已套料完成的钢板！");
        }
        List<NestSpacePlate> usedSpacePlateList = nestSpacePlateMapper.lambdaQuery().in(NestSpacePlate::getPlateCode, reqVo.getPlateList()).in(NestSpacePlate::getStatus, 3, 4, 5).list();
        Map<String, NestSpacePlate> usedSpacePlateMap = usedSpacePlateList.stream().collect(Collectors.toMap(NestSpacePlate::getPlateCode, Function.identity()));

        for (String plateCode : reqVo.getPlateList()) {
            NestSpacePlate usedPlate = usedSpacePlateMap.get(plateCode);
            if (ObjectUtils.isNotEmpty(usedPlate)) {
                usedPlate.setStatus(1);
                nestSpacePlateMapper.updateById(usedPlate);
            } else {
                NestSpacePlate nestSpacePlate = new NestSpacePlate();
                nestSpacePlate.setSpaceId(reqVo.getSpaceId());
                nestSpacePlate.setPlateCode(plateCode);
                nestSpacePlate.setStatus(1);
                nestSpacePlate.setCount(0);
                nestSpacePlateMapper.insert(nestSpacePlate);
            }
        }

        if (StringUtils.hasText(nestSpace.getLantekCode())) {
            NestRule nestRule = strategyConfig.getNestRule(NestRule.LANTEK);
            nestRule.platesPush(reqVo.getSpaceId(), reqVo.getPlateList());
        }

    }

    public void plateOut(BaseIdReqVo reqVo) {
        NestSpacePlate nestSpacePlate = nestSpacePlateMapper.selectById(reqVo.getId());
        if (nestSpacePlate == null) {
            throw SyExceptionUtils.e("钢板不存在");
        }

        if (nestSpacePlate.getStatus() != 1) {
            throw SyExceptionUtils.e("状态异常，钢板不支持移除！");
        }

        nestSpacePlateMapper.deleteHardById(nestSpacePlate.getId());

    }

    public void pushPartAdd(BaseIdsReqVo reqVo) {
        NestRule nestRule = strategyConfig.getNestRule(NestRule.LANTEK);

        List<OrderBom> orderBomList = orderBomMapper.lambdaQuery().in(OrderBom::getOrderId, reqVo.getIds()).eq(OrderBom::getMaterType, "Platepart").list();
        nestRule.partAdd(orderBomList);
    }

    public void pushPartPush() {
        NestRule nestRule = strategyConfig.getNestRule(NestRule.LANTEK);
        nestRule.partPush();
    }

    public void pushPlanAdd(BaseIdsReqVo reqVo) {
        List<String> qgPhaseList = new ArrayList<>();
        qgPhaseList.add("JG");
        qgPhaseList.add("HG");

        NestRule nestRule = strategyConfig.getNestRule(NestRule.LANTEK);

        for (Integer orderId : reqVo.getIds()) {
            // 获取所有需要切割的零件
            List<ApsWorkDetail> apsWorkDetailList = apsWorkDetailMapper.lambdaQuery()
                    .eq(ApsWorkDetail::getOrderId, orderId).eq(ApsWorkDetail::getStatus, 2)
                    .eq(ApsWorkDetail::getType, 2)
                    .in(ApsWorkDetail::getPhaseCode, qgPhaseList)
                    .list();

            if (CollUtil.isEmpty(apsWorkDetailList)) {
                throw SyExceptionUtils.e("未查询到需要套料的零件信息");
            }

            Order order = orderMapper.selectById(orderId);

            // 状态 6 未套料，7 已至少推送过一次套料
            if (order.getOrderStatus() < 6) {
                throw SyExceptionUtils.e("订单状态不正确，无法套料");
            } else if (order.getOrderStatus() == 6 || order.getOrderStatus() == 7) {
                nestRule.planAdd(apsWorkDetailList, null, null);
            } else {
                throw SyExceptionUtils.e("已套料，无法再次套料");
            }
        }
    }

    public void pushManHex(NestProPushHexReqVo reqVo) {
        if (CollUtil.isEmpty(reqVo.getNestPlanId())) {
            throw SyExceptionUtils.e("未选择下料计划。");
        }
        List<SinoCamPushPlan> pushPlanList = sinoCamPushPlanMapper.lambdaQuery().in(SinoCamPushPlan::getNestPlanId, reqVo.getNestPlanId()).list();
//        List<Order> orderList = orderMapper.lambdaQuery().in(Order::getId, pushPlanList.stream().map(SinoCamPushPlan::getOrderId).collect(Collectors.toList())).list();
//        if (orderList.stream().anyMatch(e->e.getPushType()!= null)) {
//            throw SyExceptionUtils.e("订单推送类型已存在，订单已推送过！");
//        }
        if (pushPlanList.stream().anyMatch(e->e.getPushType()!= null)) {
            throw SyExceptionUtils.e("存在已推送过的下料计划！");
        }

        List<HexagonPackagePush> packagePushList = hexagonNestRule.converterAndSave(reqVo, pushPlanList);

        hexagonNestRule.sendToMesAll(reqVo, packagePushList);

    }

    public void pushManLan(NestProPushLanReqVo reqVo) {
        List<SinoCamPushPlan> pushPlanList = sinoCamPushPlanMapper.lambdaQuery().in(SinoCamPushPlan::getNestPlanId, reqVo.getNestPlanIds()).list();
        List<Order> orderList = orderMapper.lambdaQuery().in(Order::getId, pushPlanList.stream().map(SinoCamPushPlan::getOrderId).collect(Collectors.toList())).list();
        if (orderList.stream().anyMatch(e->e.getPushType()!= null)) {
            throw SyExceptionUtils.e("订单推送类型已存在，订单已推送过！");
        }

        sinoCamPushPlanMapper.lambdaUpdate()
                .in(SinoCamPushPlan::getNestPlanId, reqVo.getNestPlanIds())
                .set(SinoCamPushPlan::getPushType, 2)
                .set(SinoCamPushPlan::getStatus, 4)
                .update();

        for (Order order : orderList) {
            order.setPushStatus(2);
            order.setOrderStatus(7);
            orderMapper.updateById(order);
        }
    }

    public void pushManAllHex(NestProPushHexAllReqVo reqVo) {
        Order order = orderMapper.selectById(reqVo.getOrderId());
        if (order.getPushType() != null) {
            throw SyExceptionUtils.e("订单推送类型已存在，订单已推送过！");
        }

        hexagonNestRule.valid(reqVo);

        List<HexagonPackagePush> packagePushList = hexagonNestRule.converterAndSave(reqVo);

//        hexagonNestRule.sendToMesAll(reqVo, packagePushList);

    }

    public void pushManAllLan(NestProPushLanAllReqVo reqVo) {
        Order order = orderMapper.selectById(reqVo.getOrderId());
        if (order.getPushType() != null) {
            throw SyExceptionUtils.e("订单推送类型已存在，订单已推送过！");
        }

        sinoCamPushPlanMapper.lambdaUpdate()
                .eq(SinoCamPushPlan::getOrderId, reqVo.getOrderId())
                .set(SinoCamPushPlan::getPushType, 2)
                .set(SinoCamPushPlan::getStatus, 4)
                .update();

        order.setPushStatus(2);
        order.setPushType(2);
        order.setOrderStatus(7);
        orderMapper.updateById(order);
    }

    public void pushManRePush(NestProPushLanReqVo reqVo) {
        List<SinoCamPushPlan> pushPlanList = sinoCamPushPlanMapper.lambdaQuery().in(SinoCamPushPlan::getNestPlanId, reqVo.getNestPlanIds()).list();
        if (pushPlanList.stream().anyMatch(e -> e.getStatus() != 5)) {
            throw SyExceptionUtils.e("所选计划非全失败。");
        }
        List<SinoCamPushPlan> hexPushPlanList = pushPlanList.stream().filter(e -> e.getPushType() == 1).collect(Collectors.toList());
        List<SinoCamPushPlan> lanPushPlanList = pushPlanList.stream().filter(e -> e.getPushType() == 2).collect(Collectors.toList());

        if (CollUtil.isNotEmpty(lanPushPlanList)) {
            List<NestSpacePart> spacePartList = nestSpacePartMapper.lambdaQuery().in(NestSpacePart::getPartPlanId, lanPushPlanList.stream().map(SinoCamPushPlan::getId).collect(Collectors.toList())).in(NestSpacePart::getStatus, 1, 2).list();
            Map<Integer, NestSpacePart> spacePartMap = spacePartList.stream().collect(Collectors.toMap(NestSpacePart::getId, v -> v));
            List<NestSpace> spaceList = nestSpaceMapper.lambdaQuery().in(NestSpace::getId, spacePartList.stream().map(NestSpacePart::getSpaceId).collect(Collectors.toList())).list();
            Map<Integer, NestSpace> spaceMap = spaceList.stream().collect(Collectors.toMap(NestSpace::getId, v -> v));
            List<LantekProPlanInfoVo> voList = new ArrayList<>();
            // 兰特克重新推送
            for (SinoCamPushPlan pushPlan : lanPushPlanList) {
                LantekProPlanInfoVo vo = new LantekProPlanInfoVo();
                NestSpacePart nestSpacePart = spacePartMap.get(pushPlan.getId());
                NestSpace nestSpace = spaceMap.get(nestSpacePart.getSpaceId());

                vo.setPlanId(pushPlan.getNestPlanId());
                vo.setUniMaterCode(pushPlan.getUniMaterCode());
                vo.setPackageCode(pushPlan.getProcessingNo());
                vo.setPlanAmount(nestSpacePart.getTotalCount());
                vo.setNeedDateTime(String.valueOf(pushPlan.getNeedDate()));
                vo.setTexture(pushPlan.getReplaceTexture());
                vo.setThickness(String.valueOf(pushPlan.getReplaceThickness()));
                vo.setDxfPath(null);
                vo.setOrderId(pushPlan.getOrderId() + "_1");

                voList.add(vo);
            }
        }

        if (CollUtil.isNotEmpty(hexPushPlanList)) {
            // 海克斯康重新推送
            for (SinoCamPushPlan pushPlan : hexPushPlanList) {

            }
        }

    }

    public void releasePart(BaseIdReqVo reqVo) {
        NestSpace nestSpace = nestSpaceMapper.selectById(reqVo.getId());
        List<NestSpacePart> spacePartList = nestSpacePartMapper.lambdaQuery().eq(NestSpacePart::getSpaceId, reqVo.getId()).list();

        if (CollUtil.isEmpty(spacePartList)) {
            return;
        }

        List<SinoCamPushPlan> pushPlanList = sinoCamPushPlanMapper.selectBatchIds(spacePartList.stream().map(NestSpacePart::getPartPlanId).collect(Collectors.toList()));
        Map<Integer, SinoCamPushPlan> pushPlanMap = pushPlanList.stream().collect(Collectors.toMap(SinoCamPushPlan::getId, v -> v));

        List<NestReleasePartInfoVo> orders = new ArrayList<>();
        for (NestSpacePart nestSpacePart : spacePartList) {
            if (nestSpacePart.getFinishCount() == 0) {
                nestSpacePartMapper.deleteHardById(nestSpacePart.getId());
            } else {
                nestSpacePart.setStatus(3);
                nestSpacePartMapper.updateById(nestSpacePart);
            }
            SinoCamPushPlan sinoCamPushPlan = pushPlanMap.get(nestSpacePart.getPartPlanId());
            NestReleasePartInfoVo plan = new NestReleasePartInfoVo();
            plan.setPlanId(sinoCamPushPlan.getNestPlanId());
            orders.add(plan);
        }
        NestReleasePartReqVo partRelease = new NestReleasePartReqVo();
        partRelease.setJobRef(nestSpace.getLantekCode());
        partRelease.setOrders(orders);
        partRelease.setUsername("TEST01");
        NestLanPaReleaseResVo proPart = lantekProApiClient.release(partRelease, LtkPushTokenDto.TOKEN);
    }

    public void releasePlate(BaseIdReqVo reqVo) {
        NestSpace nestSpace = nestSpaceMapper.selectById(reqVo.getId());
        List<NestSpacePlate> spacePlateList = nestSpacePlateMapper.lambdaQuery().eq(NestSpacePlate::getSpaceId, reqVo.getId()).eq(NestSpacePlate::getStatus, 2).list();

        if (CollUtil.isEmpty(spacePlateList)) {
            return;
        }
        List<String> prdRefs = spacePlateList.stream().map(NestSpacePlate::getPlateCode).collect(Collectors.toList());
        NestReleasePlateReqVo plateRelease = new NestReleasePlateReqVo();
        plateRelease.setJobRef(nestSpace.getLantekCode());
        plateRelease.setPrdRefs(prdRefs);
        NestLanPlReleaseResVo proPlate = lantekProApiClient.releaseAPSIntegratedInventory(plateRelease, LtkPushTokenDto.TOKEN);

        if (proPlate.getCode() == 200) {
            for (NestSpacePlate plate : spacePlateList) {
                nestSpacePlateMapper.deleteHardById(plate.getId());
            }
            LantekLockStockReqVo plateUnlockVo = new LantekLockStockReqVo();
            plateUnlockVo.setPlateList(prdRefs);
            apsWmsApiClient.pushLanUnlock(plateUnlockVo);
        } else {
            throw SyExceptionUtils.e("钢板释放通知兰特克失败：{}", proPlate.getMessage());
        }
    }

    @Transactional
    public void releasePartOne(BaseIdReqVo reqVo) {
        NestSpacePart nestSpacePart = nestSpacePartMapper.selectById(reqVo.getId());
        if (nestSpacePart.getStatus() != 2) {
            throw SyExceptionUtils.e("状态错误，无法释放.");
        }
        NestSpace nestSpace = nestSpaceMapper.selectById(nestSpacePart.getSpaceId());

        List<NestReleasePartInfoVo> orders = new ArrayList<>();
        SinoCamPushPlan sinoCamPushPlan = sinoCamPushPlanMapper.selectById(nestSpacePart.getPartPlanId());
        NestReleasePartInfoVo plan = new NestReleasePartInfoVo();
        plan.setPlanId(sinoCamPushPlan.getNestPlanId());
        orders.add(plan);
        NestReleasePartReqVo partRelease = new NestReleasePartReqVo();
        partRelease.setJobRef(nestSpace.getLantekCode());
        partRelease.setOrders(orders);
        partRelease.setUsername(nestSpace.getCreateUsername());
        NestLanPaReleaseResVo proPart = lantekProApiClient.release(partRelease, LtkPushTokenDto.TOKEN);

        if (proPart.getCode() == 200) {
            nestSpacePart.setStatus(3);
            nestSpacePartMapper.updateById(nestSpacePart);
        } else {
            throw SyExceptionUtils.e("零件释放通知兰特克失败：{}", proPart.getMessage());
        }
    }

    @Transactional
    public void releasePlateOne(BaseIdReqVo reqVo) {
        NestSpacePlate nestSpacePlate = nestSpacePlateMapper.selectById(reqVo.getId());
        if (nestSpacePlate.getStatus() != 2) {
            throw SyExceptionUtils.e("状态错误，无法释放.");
        }
        NestSpace nestSpace = nestSpaceMapper.selectById(nestSpacePlate.getSpaceId());

        List<String> prdRefs = new ArrayList<>();
        prdRefs.add(nestSpacePlate.getPlateCode());
        NestReleasePlateReqVo plateRelease = new NestReleasePlateReqVo();
        plateRelease.setJobRef(nestSpace.getLantekCode());
        plateRelease.setPrdRefs(prdRefs);
        NestLanPlReleaseResVo proPlate = lantekProApiClient.releaseAPSIntegratedInventory(plateRelease, LtkPushTokenDto.TOKEN);

        if (proPlate.getCode() == 200) {
            nestSpacePlate.setStatus(3);
            nestSpacePlateMapper.updateById(nestSpacePlate);

            LantekLockStockReqVo plateUnlockVo = new LantekLockStockReqVo();
            plateUnlockVo.setPlateList(prdRefs);
            apsWmsApiClient.pushLanUnlock(plateUnlockVo);
        } else {
            throw SyExceptionUtils.e("钢板释放通知兰特克失败：{}", proPlate.getMessage());
        }
    }

    @Transactional
    public void releasePlateLan(List<NestReleasePlateVo> list) {
        /*NestSpace nestSpace = nestSpaceMapper.lambdaQuery().eq(NestSpace::getLantekCode, reqVo.getJobRef()).one();
        nestSpacePlateMapper.lambdaUpdate()
                .eq(NestSpacePlate::getSpaceId, nestSpace.getId())
                .in(NestSpacePlate::getPlateCode, reqVo.getPrdRefs())
                .set(NestSpacePlate::getStatus, 3)
                .update();*/
        List<String> collect = list.stream().map(NestReleasePlateVo::getPlateCode).collect(Collectors.toList());
        nestSpacePlateMapper.lambdaUpdate()
                .eq(NestSpacePlate::getStatus, 2)
                .in(NestSpacePlate::getPlateCode, collect)
                .set(NestSpacePlate::getStatus, 3)
                .update();
    }

    @Transactional
    public void releasePlanLan(NestReleasePartVo reqVo) {
        /*NestSpace nestSpace = nestSpaceMapper.lambdaQuery().eq(NestSpace::getLantekCode, reqVo.getJobRef()).one();
        List<SinoCamPushPlan> pushPlanList = sinoCamPushPlanMapper.lambdaQuery().in(SinoCamPushPlan::getNestPlanId, reqVo.getOrders().stream().map(NestReleasePartInfoVo::getPlanId).collect(Collectors.toList())).list();
        nestSpacePartMapper.lambdaUpdate()
                .eq(NestSpacePart::getSpaceId, nestSpace.getId())
                .in(NestSpacePart::getPartPlanId, pushPlanList.stream().map(SinoCamPushPlan::getId).collect(Collectors.toList()))
                .set(NestSpacePart::getStatus, 3)
                .update();*/
        List<String> pushPlanIds = reqVo.getPart().stream().map(NestReleasePartListVo::getPlanId).collect(Collectors.toList());
        List<SinoCamPushPlan> pushPlanList = sinoCamPushPlanMapper.lambdaQuery().in(SinoCamPushPlan::getNestPlanId, pushPlanIds).list();

        NestSpace nestSpace = nestSpaceMapper.lambdaQuery().eq(NestSpace::getLantekCode, reqVo.getJobRef()).one();
        List<NestSpacePart> spacePartList = nestSpacePartMapper.lambdaQuery().eq(NestSpacePart::getSpaceId, nestSpace.getId())
                .in(NestSpacePart::getPartPlanId, pushPlanList.stream().map(SinoCamPushPlan::getId).collect(Collectors.toList()))
                .list();

        List<NestReleasePartListVo> releaseParts = reqVo.getPart();
        Map<String, NestReleasePartListVo> releasePartMap = releaseParts.stream().collect(Collectors.toMap(NestReleasePartListVo::getPlanId, v -> v));
        Map<Integer, SinoCamPushPlan> pushPlanMap = pushPlanList.stream().collect(Collectors.toMap(SinoCamPushPlan::getId, v -> v));

        if (StringUtils.hasText(nestSpace.getLantekRequestId()) && nestSpace.getLantekRequestId().contains(reqVo.getRequestId())) {
            return;
        }

        for (NestSpacePart part : spacePartList) {
            SinoCamPushPlan pushPlan = pushPlanMap.get(part.getPartPlanId());
            NestReleasePartListVo releasePart = releasePartMap.get(pushPlan.getNestPlanId());
            part.setTotalCount(part.getTotalCount() - releasePart.getQuantity());
            if (Objects.equals(part.getFinishCount(), part.getTotalCount())) {
                part.setStatus(4);
            }
            nestSpacePartMapper.updateById(part);
        }

        nestSpace.setLantekRequestId(reqVo.getRequestId());
        nestSpaceMapper.updateById(nestSpace);

        for (NestReleasePartListVo part : releaseParts) {
//            SinoCamPushPlan pushPlan = sinoCamPushPlanMapper.lambdaQuery().eq(SinoCamPushPlan::getNestPlanId, part.getPlanId()).one();
            ApsWorkDetail detail = apsWorkDetailMapper.selectById(part.getPlanId());
            ApsWorkOrder workOrder = apsWorkOrderMapper.selectById(detail.getApsWorkOrderId());
            if (workOrder.getPickSeq() != null) {
                workOrder.setPickSeq(workOrder.getPickSeq() - part.getQuantity());
                apsWorkOrderMapper.updateById(workOrder);
            }
        }

    }

    public void openNestDraw(LantekProOpenReqVo reqVo) {
        String userCode = SySecurityUtils.getUserCode();
        DictType personBind = dictTypeMapper.lambdaQuery().eq(DictType::getDictCode, "personBind").one();
        List<DictData> personBindList = dictDataMapper.lambdaQuery().eq(DictData::getDictType, personBind.getId()).list();
        Map<String, DictData> personBindMap = personBindList.stream().collect(Collectors.toMap(DictData::getDictLabel, v -> v));
        String userName = personBindMap.get(userCode).getDictValue();

        if (reqVo.getId() == null) {
            SinoCamReceiveNestPlate nestPlate = sinoCamReceiveNestPlateMapper.lambdaQuery().eq(SinoCamReceiveNestPlate::getStockListNo, reqVo.getShtRef()).one();
            SinoCamReceiveNestNest nestNest = sinoCamReceiveNestNestMapper.lambdaQuery().eq(SinoCamReceiveNestNest::getNestId, nestPlate.getNestId()).one();
            if (!StringUtils.hasText(nestNest.getLantekCode())) {
                throw SyExceptionUtils.e("该钢板不是兰特克套的：{}", reqVo.getShtRef());
            }
//        reqVo.setUsername("TEST01");
            reqVo.setUsername(userCode);
            reqVo.setJobRef(nestNest.getLantekCode());

            NestLanCommonsResVo resVo = lantekProApiClient.openNesting(reqVo, LtkPushTokenDto.TOKEN);
            log.info("打开钢板套料图结果：{}", JsonUtils.toJsonString(resVo));
            if (resVo.getCode() != 200) {
                throw SyExceptionUtils.e("打开套料图失败：{}", resVo.getMessage());
            }
        } else {
            NestSpace nestSpace = nestSpaceMapper.selectById(reqVo.getId());
            reqVo.setUsername(userCode);
            reqVo.setJobRef(nestSpace.getLantekCode());

            NestLanCommonsResVo resVo = lantekProApiClient.openNesting(reqVo, LtkPushTokenDto.TOKEN);
            log.info("打开兰特克工作区结果：{}", JsonUtils.toJsonString(resVo));
            if (resVo.getCode() != 200) {
                throw SyExceptionUtils.e("打开工作区失败：{}", resVo.getMessage());
            }

            nestSpaceMapper.lambdaUpdate()
                    .eq(NestSpace::getCreateUsername, userCode)
                    .eq(NestSpace::getStatus, 2)
                    .set(NestSpace::getStatus, 3)
                    .update();

            nestSpace.setStatus(2);
            nestSpaceMapper.updateById(nestSpace);
        }

    }

    public void nestInfoWrite(NestReceiveReqVo reqVo) {
    }

    public void pushOrderLan(NestProPushLanReqVo reqVo) {
        List<SinoCamPushPlan> pushPlanList = sinoCamPushPlanMapper.lambdaQuery().in(SinoCamPushPlan::getNestPlanId, reqVo.getNestPlanIds()).list();

        if (CollUtil.isEmpty(pushPlanList)) {
            throw SyExceptionUtils.e("未选中要推送的计划。");
        }

        List<BigDecimal> collect1 = pushPlanList.stream().map(SinoCamPushPlan::getReplaceThickness).distinct().collect(Collectors.toList());
        if (CollUtil.isNotEmpty(collect1) && collect1.size() >= 2) {
            throw SyExceptionUtils.e("推送的厚度不唯一。");
        }

        List<String> collect2 = pushPlanList.stream().map(SinoCamPushPlan::getReplaceTexture).distinct().collect(Collectors.toList());
        if (CollUtil.isNotEmpty(collect2) && collect2.size() >= 2) {
            throw SyExceptionUtils.e("推送的材质不唯一。");
        }

        List<NestSpacePart> list = nestSpacePartMapper.lambdaQuery()
                .in(NestSpacePart::getPartPlanId, pushPlanList.stream().map(SinoCamPushPlan::getId).collect(Collectors.toList()))
                .eq(NestSpacePart::getStatus, 2)
                .list();

        if(CollUtil.isNotEmpty(list)){
            DictType personBind = dictTypeMapper.lambdaQuery().eq(DictType::getDictCode, "personBind").one();
            List<DictData> personBindList = dictDataMapper.lambdaQuery().eq(DictData::getDictType, personBind.getId()).list();
            Map<String, DictData> personBindMap = personBindList.stream().collect(Collectors.toMap(DictData::getDictLabel, v -> v));
            String userName = personBindMap.get(list.get(0).getCreateUsername()).getDictValue();
            if (CollUtil.isNotEmpty(list)) {
                throw SyExceptionUtils.e("存在套料中的计划，占用人：{}", userName);
            }
        }


        NestRule nestRule = strategyConfig.getNestRule(NestRule.LANTEK);
        nestRule.planPush(pushPlanList.stream().map(SinoCamPushPlan::getId).collect(Collectors.toList()), reqVo.getGroupCode(), reqVo.getSpaceId());
    }

    public BaseListResVo<NestWorkspaceListResVo> pushSelectSpace() {
        String userCode = SySecurityUtils.getUserCode();
        List<NestSpace> nestSpace = nestSpaceMapper.lambdaQuery().eq(NestSpace::getCreateUsername, userCode).eq(NestSpace::getStatus, 2).list();
        return BaseListResVo.of(nestSpace, NestWorkspaceListResVo.class);
    }

    public void pushPlateLan(NestPlateInReqVo reqVo) {
        if (CollUtil.isEmpty(reqVo.getPlateList())) {
            throw SyExceptionUtils.e("未选择钢板。");
        }

        NestRule nestRule = strategyConfig.getNestRule(NestRule.LANTEK);
        nestRule.platesPush(null, reqVo.getPlateList());
    }

    public void createWorkPlace(String texture, Integer thickness, String groupCode) {
        lantekNestRule.createWorkPlace(texture, thickness, groupCode);
    }

    public void handPlatePost(NestPlatePushReqVo reqVo) {

        String userCode = SySecurityUtils.getUserCode();
        if ("000000".equals(userCode)) {
            userCode = reqVo.getUsername();
        }
        reqVo.setUsername(userCode);

        NestLanCommonsResVo pro = lantekProApiClient.importAPSIntegratedInventory(reqVo, LtkPushTokenDto.TOKEN);
        log.info("导入集成库存结果：{}", JsonUtils.toJsonString(pro));

        if (pro.getCode() == 200) {
            String spaceCode = reqVo.getJobRef();
            NestSpace nestSpace = nestSpaceMapper.lambdaQuery().eq(NestSpace::getLantekCode, spaceCode).one();

            for (NestPlatePushInfoVo p : reqVo.getSteelPlates()) {
                NestSpacePlate spacePlate = new NestSpacePlate();
                spacePlate.setPlateCode(p.getPlateCode());
                spacePlate.setSpaceId(nestSpace.getId());
                spacePlate.setStatus(2);
                spacePlate.setCount(1);
                nestSpacePlateMapper.insert(spacePlate);
            }

        }
    }

    public void handPostPre(Integer id) {
        List<Integer> ids = new ArrayList<>();
        ids.add(id);

        String pushType = NestRule.LANTEK_PRE;
        NestRule nestRule = strategyConfig.getNestRule(pushType);
        nestRule.planPush(ids, null, null);
    }

    public void receiveNestNewLan(String body, LogApi logApi) {

        String pushType = NestRule.LANTEK;
        NestRule nestRule = strategyConfig.getNestRule(pushType);
        NestReceiveReqVo reqVo = nestRule.nestReceiveNew(body);

        writeInTable(reqVo, logApi);

    }

    public void receiveNestNewHex(String body, LogApi logApi) {

        String pushType = NestRule.HEXAGON;
        NestRule nestRule = strategyConfig.getNestRule(pushType);
        // nestRule.receiveNestNewLan(body);
        NestReceiveReqVo reqVo = receiveNestNewHexH(body);

        writeInTable(reqVo, logApi);

    }

    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    public NestReceiveReqVo receiveNestNewHexH(String body) {

        JavaType javaType = objectMapper.getTypeFactory().constructParametricType(List.class, ReceiveNestPlateReqVo.class);
        List<ReceiveNestPlateReqVo> reqVos = objectMapper.readValue(body, javaType);
        ReceiveNestPlateReqVo reqVo = reqVos.get(0);

        return null;

    }

    @Transactional(rollbackFor = Exception.class)
    public void writeInTable(NestReceiveReqVo reqVo, LogApi logApi) {

        // 接收套料结果，数据进行回填。
        // 套料 nest（套料信息），plate（钢板信息列表），part（套料零件列表），excess（钢板余料列表），move（套料切割信息）。
        // 计划 aps_work_detail（钢板四个工序计划），plate_phase（钢板四个工序信息），mes_plate（钢板信息），mes_plate_pick（钢板领料信息），mes_work_detail_task（钢板领料任务）。
        // 计划回填 pushPlan（回填计划套料完成数量），nestSpacePart（回填作业区零件完成数量，及套料完成状态），计划状态修改（如果完成数量等于推送数量则状态置为完成）

        Map<String, List<NestReceivePart>> partMap = new HashMap<>();

        NestReceiveNest nn = nestReceiveNestMapper.lambdaQuery().eq(NestReceiveNest::getNestCode, reqVo.getNest().getNestCode()).one();
        if (nn != null) {
            throw SyExceptionUtils.e("套料图号重复：{}", reqVo.getNest().getNestCode());
        }

        // 套料
        NestReceiveNestReqVo nest = reqVo.getNest();

        NestReceiveNest nestEntity = MkBeanUtils.copyProperties(nest, NestReceiveNest.class);
        nestEntity.setLogApiId(logApi.getId());
        nestEntity.setNestCode(nest.getNestCode());
        nestEntity.setSpaceCode(nest.getJobRef());
        nestEntity.setFactoryCode("170");
        nestEntity.setNestDateTime(nest.getNestDateTime());
        nestEntity.setNeedDateTime(nest.getNeedDateTime());
        nestEntity.setNestUserCode(nest.getNestUserCode());
        nestEntity.setSplitGroupCode(nest.getSplitGroupCode());
        nestEntity.setType(nest.getType());
        nestEntity.setSource(nest.getSource());
        nestEntity.setNestDxf(nest.getNestDxf());
        nestEntity.setBookSheet(nest.getBookSheet());
        nestEntity.setReportPdf(nest.getReportPdf());
        nestEntity.setCuttingProgram(nest.getCuttingProgram());
        nestEntity.setSpaceCode(nest.getJobRef());

        nestReceiveNestMapper.insert(nestEntity);

        log.info("套料:{}", JsonUtils.toJsonString(nestEntity));

        // 零件
        List<NestReceivePart> parts = reqVo.getPart().stream()
                .map(e -> {
                    NestReceivePart part = MkBeanUtils.copyProperties(e, NestReceivePart.class);
                    String orderId = e.getOrderId();
                    String[] split = orderId.split("_");
                    part.setOrderId(Integer.parseInt(split[0]));
                    part.setPlanId(Integer.valueOf(e.getPlanId()));
                    part.setPlmId(e.getPlmId());
                    part.setMaterName(e.getMaterName());
                    part.setLength(e.getLength());
                    part.setWidth(e.getWidth());
                    part.setThickness(e.getThickness());
                    part.setArea(e.getArea());
                    part.setRectangleArea(e.getRectangleArea());
                    part.setNetWeight(e.getNetWeight());
                    part.setPartPng(e.getPartPng());
                    part.setPlateCode(e.getPlateCode());
                    part.setTotalCount(e.getTotalCount());
                    part.setSortingCount(0);// 分拣数量
                    part.setUniCode(split[0] + "#" + e.getPlmId());
                    part.setNestCode(e.getNestCode());

                    return part;
                })
                .collect(Collectors.toList());

        for (NestReceivePart part : parts) {
            partMap.computeIfAbsent(String.valueOf(part.getPlanId()), kk -> new ArrayList<>()).add(part);
        }

        nestReceivePartMapper.insertBatchSomeColumn(parts);

        log.info("零件:{}", JsonUtils.toJsonString(parts));

        // 钢板
        if (reqVo.getPlate().size() > 2) {
            throw SyExceptionUtils.e("钢板数量大于2");
        }

        List<String> collect1 = reqVo.getPlate().stream().map(NestReceivePlateReqVo::getPlateCode).collect(Collectors.toList());

        Integer count = nestReceivePlateMapper.lambdaQuery().in(NestReceivePlate::getPlateCode, collect1).count();
        if (count > 0) {
            throw SyExceptionUtils.e("钢板重复");
        }

        List<NestReceivePlate> plates = reqVo.getPlate().stream().map(e -> {
            NestReceivePlate plate = MkBeanUtils.copyProperties(e, NestReceivePlate.class);
            plate.setHeatCode(e.getHeatCode()); // 炉批号需要去 WMS 查询
            plate.setPlateCode(e.getPlateCode());
            plate.setPlateName(e.getPlateCode());
            plate.setTexture(e.getTexture());
            plate.setThickness(e.getThickness());
            plate.setLength(e.getLength());
            plate.setWidth(e.getWidth());
            plate.setRate(e.getRate());
            plate.setPlatePng(e.getPlatePng());
            plate.setPositionCode(e.getPositionCode());
            plate.setSeq(e.getSequence());
            plate.setSideLength(e.getSideLength());
            plate.setNestCode(e.getNestCode());
            plate.setNestArea(e.getNestArea());

            return plate;
        }).collect(Collectors.toList());

        nestReceivePlateMapper.insertBatchSomeColumn(plates);

        log.info("钢板:{}", JsonUtils.toJsonString(plates));

        // 余料
        if (CollUtil.isNotEmpty(reqVo.getExcess())) {
            List<NestReceiveExcess> excesses = reqVo.getExcess().stream().map(e -> {
                NestReceiveExcess excess = MkBeanUtils.copyProperties(e, NestReceiveExcess.class);
                excess.setExcessCode(e.getExcessCode());
                excess.setPlateCode(e.getPlateCode());
                excess.setLength(e.getLength());
                excess.setWidth(e.getWidth());
                excess.setTexture(e.getTexture());
                excess.setThickness(e.getThickness());
                excess.setWeight(e.getWeight());
                excess.setStorehouseId("H_0-1_GB_HC_4101");
                excess.setNestCode(e.getNestCode());
                excess.setExcessPng(e.getExcessPng());
                excess.setOutStock(0);

                return excess;
            }).collect(Collectors.toList());

            nestReceiveExcessMapper.insertBatchSomeColumn(excesses);

            log.info("余料:{}", JsonUtils.toJsonString(excesses));
        }

        // 走刀
        List<NestReceiveMove> moves = reqVo.getMove().stream().map(e -> {
            NestReceiveMove move = MkBeanUtils.copyProperties(e, NestReceiveMove.class);
            move.setMoveType(e.getMoveType());
            move.setCutLength(e.getCutLength());
            move.setMoveTime(e.getMoveTime());
            move.setCutRate(e.getCutRate());
            move.setHoleCount(e.getHoleCount());
            move.setTotalHoleTime(e.getTotalHoleTime());
            move.setHoleTime(e.getHoleTime());
            move.setTotalCutTime(e.getTotalCutTime());
            move.setNestCode(e.getNestCode());
            return move;
        }).collect(Collectors.toList());

        nestReceiveMoveMapper.insertBatchSomeColumn(moves);

        List<Integer> planIdList = reqVo.getPart().stream().map(e -> Integer.parseInt(e.getPlanId())).distinct().collect(Collectors.toList());
        List<ApsWorkDetail> apsWorkDetails = apsWorkDetailMapper.selectBatchIds(planIdList);

        // ---------- 推送到钢板信息表----
        Map<String, List<NestReceivePart>> nestPartsMap = parts.stream().collect(Collectors.groupingBy(NestReceivePart::getPlateCode));
        List<PlatePhase> platePhaseList = new ArrayList<>();
        List<ApsWorkDetail> apsWorkDetailList = new ArrayList<>();
        Map<String, PlatePhase> plateLlPhaseMap = new HashMap<>();
        List<Plate> plateList = plates.stream().map(nestPlate -> {

            List<NestReceivePart> nestParts = nestPartsMap.get(nestPlate.getPlateCode());
            Plate plate = new Plate();
            plate.setMaterCode(nestPlate.getPlateCode());// 钢板编号
            plate.setMaterName(nestPlate.getPlateName());// 钢板物料名称
            plate.setLength(nestPlate.getLength());
            plate.setWidth(nestPlate.getWidth());
            plate.setNorm(String.valueOf(nestPlate.getThickness()));// 厚度
            plate.setTexture(nestPlate.getTexture());
            plate.setStatus(1);
            plate.setHeatNumber(nestPlate.getHeatCode());

            plate.setNestId(nest.getNestCode());
            plate.setNestWeight(nestParts.stream().map(part -> part.getNetWeight().multiply(new BigDecimal(part.getTotalCount()))).reduce(BigDecimal.ZERO, BigDecimal::add));
            plate.setNestRate(nestPlate.getRate());// 利用率
            plate.setNestDateTime(LocalDate.parse(nest.getNestDateTime(), DatePattern.NORM_DATETIME_FORMATTER).atStartOfDay());// 套料日期
            plate.setNestingDrawing(nestPlate.getPlatePng());// 套料图纸，PNG格式
            plate.setCutProcess(nest.getCuttingProgram());// 切割程序下载地址
            // 钢板重量，长*宽*高*密度(7.85)单位 kg
            plate.setWeight(PlateWeightUtils.getPlateWeight(plate.getLength(), plate.getWidth(), plate.getNorm())); // 单位 千克
            plate.setNestPlateId(nestPlate.getId());
            plate.setPhaseCode(WorkshopProp.YC_PHASE_CODE);

            PlatePhase llPhase = new PlatePhase();
            llPhase.setPlateCode(plate.getMaterCode());
            llPhase.setPhaseCode(WorkshopProp.LL_PHASE_CODE);
            llPhase.setPhaseName(WorkshopProp.LL_PHASE_NAME);
            llPhase.setGroupCode(WorkshopProp.LL_GROUP);
            llPhase.setPhaseSeq(platePhaseList.size() + 1);
            platePhaseList.add(llPhase);


            ApsWorkDetail llApsWorkDetail = new ApsWorkDetail();
            llApsWorkDetail.setMaterNo(plate.getMaterCode());
            llApsWorkDetail.setMaterName("钢板");
            llApsWorkDetail.setPhaseId(llPhase.getPhaseSeq());
            llApsWorkDetail.setPhaseSeq(llPhase.getPhaseSeq());
            llApsWorkDetail.setPhaseCode(WorkshopProp.LL_PHASE_CODE);
            llApsWorkDetail.setPartCount(new BigDecimal(1));
            llApsWorkDetail.setFinishCount(new BigDecimal(0));
            llApsWorkDetail.setTotalCount(new BigDecimal(1));
            llApsWorkDetail.setUniqueCode(plate.getMaterCode());
            llApsWorkDetail.setStatus(2);
            llApsWorkDetail.setPhaseName(WorkshopProp.LL_PHASE_NAME);
            llApsWorkDetail.setPlanStartDateTime(DateUtils.parse(nest.getNeedDateTime(), DatePattern.NORM_DATETIME_FORMATTER).toLocalDateTime().minusHours(7));
            llApsWorkDetail.setPlanEndDateTime(DateUtils.parse(nest.getNeedDateTime(), DatePattern.NORM_DATETIME_FORMATTER).toLocalDateTime().minusHours(6));
            llApsWorkDetail.setGroupCode(WorkshopProp.LL_GROUP);
            llApsWorkDetail.setAppendFlag(2);
            llApsWorkDetail.setType(1);
            llApsWorkDetail.setTotalWorkTime(60 * 60);
            llApsWorkDetail.setWorkTime(60 * 60);
            if (CollUtil.isNotEmpty(apsWorkDetails)) {
                llApsWorkDetail.setOrderId(apsWorkDetails.get(0).getOrderId());
                llApsWorkDetail.setApsOrderId(apsWorkDetails.get(0).getApsOrderId());
            }
            apsWorkDetailList.add(llApsWorkDetail);

            plateLlPhaseMap.put(plate.getMaterCode(), llPhase);


            // 添加预处理工序
            BigDecimal thickness = new BigDecimal(plate.getNorm());
            if (thickness.compareTo(new BigDecimal(100)) < 0) { //钢板厚度小于100走预处理
                PlatePhase phase = new PlatePhase();
                phase.setPlateCode(plate.getMaterCode());
                phase.setPhaseCode(WorkshopProp.YC_PHASE_CODE);
                phase.setPhaseName("预处理");
                phase.setGroupCode(WorkshopProp.YC_GROUP);
                phase.setPhaseSeq(platePhaseList.size() + 1);
                platePhaseList.add(phase);
                ApsWorkDetail ycApsWorkDetail = new ApsWorkDetail();
                ycApsWorkDetail.setMaterNo(plate.getMaterCode());
                ycApsWorkDetail.setMaterName("钢板");
                ycApsWorkDetail.setPhaseId(phase.getPhaseSeq());
                ycApsWorkDetail.setPhaseSeq(phase.getPhaseSeq());
                ycApsWorkDetail.setPhaseCode(WorkshopProp.YC_PHASE_CODE);
                ycApsWorkDetail.setPartCount(new BigDecimal(1));
                ycApsWorkDetail.setFinishCount(new BigDecimal(0));
                ycApsWorkDetail.setTotalCount(new BigDecimal(1));
                ycApsWorkDetail.setUniqueCode(plate.getMaterCode());
                ycApsWorkDetail.setStatus(2);
                ycApsWorkDetail.setPhaseName("预处理");
                ycApsWorkDetail.setPlanStartDateTime(DateUtils.parse(nest.getNeedDateTime(), DatePattern.NORM_DATETIME_FORMATTER).toLocalDateTime().minusHours(7));
                ycApsWorkDetail.setPlanEndDateTime(DateUtils.parse(nest.getNeedDateTime(), DatePattern.NORM_DATETIME_FORMATTER).toLocalDateTime().minusHours(6));
                ycApsWorkDetail.setGroupCode(WorkshopProp.YC_GROUP);
                ycApsWorkDetail.setAppendFlag(2);
                ycApsWorkDetail.setType(1);
                ycApsWorkDetail.setTotalWorkTime(60 * 60);
                ycApsWorkDetail.setWorkTime(60 * 60);
                if (CollUtil.isNotEmpty(apsWorkDetails)) {
                    ycApsWorkDetail.setOrderId(apsWorkDetails.get(0).getOrderId());
                    ycApsWorkDetail.setApsOrderId(apsWorkDetails.get(0).getApsOrderId());
                }
                apsWorkDetailList.add(ycApsWorkDetail);
            }

            // 添加切割工序
            PlatePhase splitPhase = new PlatePhase();
            splitPhase.setPlateCode(plate.getMaterCode());
            String phaseCode = getSplitCode(nest.getSplitGroupCode());
            splitPhase.setPhaseCode(phaseCode);
            splitPhase.setPhaseName(phaseCode.equals("JG") ? "激光切割" : "火焰切割");
            splitPhase.setGroupCode(nest.getSplitGroupCode());
            splitPhase.setPhaseSeq(platePhaseList.size() + 1);
            splitPhase.setWorkTime(reqVo.getMove().get(0).getTotalCutTime());
            platePhaseList.add(splitPhase);

            ApsWorkDetail qgApsWorkDetail = new ApsWorkDetail();
            qgApsWorkDetail.setMaterNo(plate.getMaterCode());
            qgApsWorkDetail.setMaterName("钢板");
            qgApsWorkDetail.setPhaseId(splitPhase.getPhaseSeq());
            qgApsWorkDetail.setPhaseSeq(splitPhase.getPhaseSeq());
            qgApsWorkDetail.setPhaseCode(phaseCode);
            qgApsWorkDetail.setPartCount(new BigDecimal(1));
            qgApsWorkDetail.setFinishCount(new BigDecimal(0));
            qgApsWorkDetail.setTotalCount(new BigDecimal(1));
            qgApsWorkDetail.setUniqueCode(plate.getMaterCode());
            qgApsWorkDetail.setStatus(2);
            qgApsWorkDetail.setPhaseName(phaseCode.equals("JG") ? "激光切割" : "火焰切割");
            qgApsWorkDetail.setPlanStartDateTime(DateUtils.parse(nest.getNeedDateTime(), DatePattern.NORM_DATETIME_FORMATTER).toLocalDateTime());
            qgApsWorkDetail.setPlanEndDateTime(DateUtils.parse(nest.getNeedDateTime(), DatePattern.NORM_DATETIME_FORMATTER).toLocalDateTime().plusHours(2));
            qgApsWorkDetail.setGroupCode(nest.getSplitGroupCode());
            qgApsWorkDetail.setAppendFlag(2);
            qgApsWorkDetail.setType(1);
            if (CollUtil.isNotEmpty(apsWorkDetails)) {
                qgApsWorkDetail.setOrderId(apsWorkDetails.get(0).getOrderId());
                qgApsWorkDetail.setApsOrderId(apsWorkDetails.get(0).getApsOrderId());
            }
            qgApsWorkDetail.setTotalWorkTime(2 * 60 * 60);
            qgApsWorkDetail.setWorkTime(2 * 60 * 60);
            apsWorkDetailList.add(qgApsWorkDetail);

            // 添加分捡工序
            Map<String, String> fjGroup = new HashMap<>();
            fjGroup.put("1-1_FHQG_00", "1-1_RGFJ_00");
            fjGroup.put("1-1_HYQG_00", "1-1_RGFJ_00");
            fjGroup.put("1-2_JGQG_00", "1-2_ZDFJ_00");
            fjGroup.put("1-3_JGQG_00", "1-3_ZDFJ_00");

            PlatePhase fjPhase = new PlatePhase();
            fjPhase.setPlateCode(plate.getMaterCode());
            fjPhase.setPhaseCode(WorkshopProp.FJ_PHASE_CODE);
            fjPhase.setPhaseName("分捡");
            fjPhase.setGroupCode(fjGroup.get(nest.getSplitGroupCode()));
            fjPhase.setPhaseSeq(platePhaseList.size() + 1);
            platePhaseList.add(fjPhase);

            ApsWorkDetail fjApsWorkDetail = new ApsWorkDetail();
            fjApsWorkDetail.setMaterNo(plate.getMaterCode());
            fjApsWorkDetail.setMaterName("钢板");
            fjApsWorkDetail.setPhaseId(fjPhase.getPhaseSeq());
            fjApsWorkDetail.setPhaseSeq(fjPhase.getPhaseSeq());
            fjApsWorkDetail.setPhaseCode(WorkshopProp.FJ_PHASE_CODE);
            fjApsWorkDetail.setPartCount(new BigDecimal(1));
            fjApsWorkDetail.setFinishCount(new BigDecimal(0));
            fjApsWorkDetail.setTotalCount(new BigDecimal(1));
            fjApsWorkDetail.setUniqueCode(plate.getMaterCode());
            fjApsWorkDetail.setStatus(2);
            fjApsWorkDetail.setPhaseName("分捡");
            fjApsWorkDetail.setPlanStartDateTime(DateUtils.parse(nest.getNeedDateTime(), DatePattern.NORM_DATETIME_FORMATTER).toLocalDateTime().plusHours(2));
            fjApsWorkDetail.setPlanEndDateTime(DateUtils.parse(nest.getNeedDateTime(), DatePattern.NORM_DATETIME_FORMATTER).toLocalDateTime().plusHours(5));
            fjApsWorkDetail.setGroupCode(fjGroup.get(nest.getSplitGroupCode()));
            fjApsWorkDetail.setAppendFlag(2);
            fjApsWorkDetail.setType(1);

            fjApsWorkDetail.setTotalWorkTime(3 * 60 * 60);
            fjApsWorkDetail.setWorkTime(3 * 60 * 60);
            if (CollUtil.isNotEmpty(apsWorkDetails)) {
                fjApsWorkDetail.setOrderId(apsWorkDetails.get(0).getOrderId());
                fjApsWorkDetail.setApsOrderId(apsWorkDetails.get(0).getApsOrderId());
            }
            apsWorkDetailList.add(fjApsWorkDetail);

            plate.setWorkChain(platePhaseList.stream().map(PlatePhase::getPhaseCode).collect(Collectors.joining("-")));
            return plate;
        }).collect(Collectors.toList());
        plateMapper.insertBatchSomeColumn(plateList);
        plateLlPhaseMap.forEach(this::makeLingliao);
        List<Plate> plateIdList = plateMapper.lambdaQuery().in(Plate::getMaterCode, plates.stream().map(NestReceivePlate::getPlateCode).collect(Collectors.toList())).list();
        Map<String, Plate> plateIdMap = plateIdList.stream().collect(Collectors.toMap(Plate::getMaterCode, e -> e));
        for (PlatePhase platePhase : platePhaseList) {
            platePhase.setPlateId(plateIdMap.get(platePhase.getPlateCode()).getId());
        }
        platePhaseMapper.insertBatchSomeColumn(platePhaseList);

        apsWorkDetailMapper.insertBatchSomeColumn(apsWorkDetailList);

        Map<String, Plate> collect = plateList.stream().collect(Collectors.toMap(Plate::getMaterCode, e -> e));

        Map<String, NestReceivePlateReqVo> pickInfoMap = reqVo.getPlate().stream().collect(Collectors.toMap(NestReceivePlateReqVo::getPlateCode, e->e));
        // 领料表
        List<WmsPlatePick> platePickList = plates.stream()
                .map(e -> {
                    WmsPlatePick pick = new WmsPlatePick();

                    pick.setPlateState(1);
                    pick.setNextWorkPlace(nest.getSplitGroupCode());
                    pick.setNestPlateId(e.getId());
                    pick.setAmount(1);// 数量
                    pick.setLength(e.getLength());
                    pick.setWidth(e.getWidth());
                    pick.setFastFlag(0);
                    pick.setReceiveDate(LocalDateTime.now());
                    pick.setPlannedStartTime(DateUtils.parse(nest.getNeedDateTime(), DatePattern.NORM_DATETIME_FORMATTER).toLocalDateTime().minusHours(7));// 领料时间
                    pick.setType(1);
                    pick.setMaterialCode(e.getPlateCode());// 厚度
                    pick.setPlateMaterial(e.getTexture());
                    pick.setPlateThick(String.valueOf(e.getThickness()));// 厚度
                    pick.setMaterialId(e.getPlateCode());// 钢板编号（钢板物料号/材料编号？）
                    pick.setPlateUsage(e.getRate());// 利用率
                    pick.setNesting(e.getPlatePng());// 套料图号
                    pick.setMaterName(e.getPlateCode());// 钢板物料名称

                    Plate plate = collect.get(e.getPlateCode());// 钢板编号

                    NestReceivePlateReqVo pickInfo = pickInfoMap.get(e.getPlateCode());

                    pick.setPickingListNo(pickInfo.getPickCode());
                    pick.setPickListItem(pickInfo.getPickSeq());
                    pick.setPlanDate(null);
                    pick.setPackageSn(null);
                    pick.setWantDeliverDate(null);
                    pick.setStoragePlace(e.getPositionCode());
                    pick.setSeq(e.getSeq());
                    pick.setPlateWeight(plate.getWeight());// 钢板重量
                    pick.setCloutWeight(null);
                    pick.setOutTime(null);
                    pick.setPlateNote(null);
                    pick.setPlateId(plate.getId());// 钢板ID
                    pick.setPlannedStartTime(LocalDate.parse(nest.getNeedDateTime(), DatePattern.NORM_DATETIME_FORMATTER).atStartOfDay());// 需求日期
                    pick.setNestId(e.getNestCode());
                    return pick;
                })
                .collect(Collectors.toList());
        wmsPlatePickMapper.insertBatchSomeColumn(platePickList);

        NestSpace nestSpace = new NestSpace();
        if (StringUtils.hasText(nest.getJobRef())) {
            nestSpace = nestSpaceMapper.lambdaQuery().eq(NestSpace::getLantekCode, nest.getJobRef()).one();
        }

        // 更新计划信息
        for (String nestPlanId : partMap.keySet()) {
            SinoCamPushPlan one = sinoCamPushPlanMapper.lambdaQuery().eq(SinoCamPushPlan::getNestPlanId, nestPlanId).one();
            if (one == null) {
                throw SyExceptionUtils.e("推送计划不存在，nestPlanId:{}", nestPlanId);
            }
            int sum = partMap.get(nestPlanId).stream().mapToInt(NestReceivePart::getTotalCount).sum();

            BigDecimal cha = one.getPlanAmount()
                    .subtract(one.getPlanFinishAmount())
                    .subtract(new BigDecimal(sum));

            if (cha.compareTo(new BigDecimal(0)) == 0) {
                one.setConsumeStatus(2);
                one.setPlanFinishAmount(new BigDecimal(sum).add(one.getPlanFinishAmount()));
            } else if (cha.compareTo(new BigDecimal(0)) > 0) {
                one.setConsumeStatus(1);
                one.setPlanFinishAmount(new BigDecimal(sum).add(one.getPlanFinishAmount()));
            } else {
                throw SyExceptionUtils.e("套料异常，零件{}需要{}个，已套{}，待套{}，数量超了", one.getPartName(), one.getPlanAmount(), one.getPlanFinishAmount(), sum);
            }

            sinoCamPushPlanMapper.lambdaUpdate()
                    .eq(SinoCamPushPlan::getId, one.getId())
                    .set(SinoCamPushPlan::getStatus, one.getStatus())
                    .set(SinoCamPushPlan::getPlanFinishAmount, one.getPlanFinishAmount())
                    .set(SinoCamPushPlan::getModifyDateTime, LocalDateTime.now())
                    .update();

            if (StringUtils.hasText(nest.getJobRef())) {
                NestSpacePart nestSpacePart = nestSpacePartMapper.lambdaQuery()
                        .eq(NestSpacePart::getPartPlanId, one.getId())
                        .eq(NestSpacePart::getSpaceId, nestSpace.getId())
                        .eq(NestSpacePart::getStatus, 2)
                        .one();
                if (nestSpacePart == null) {
                    throw SyExceptionUtils.e("绑定计划不存在，nestPlanId:{}", nestPlanId);
                }
                int sub = nestSpacePart.getTotalCount() - nestSpacePart.getFinishCount() - sum;
                if (sub == 0) {
                    nestSpacePart.setStatus(4);
                    nestSpacePart.setFinishCount(nestSpacePart.getFinishCount() + sum);
                } else if (sub > 0) {
                    nestSpacePart.setStatus(2);
                    nestSpacePart.setFinishCount(nestSpacePart.getFinishCount() + sum);
                } else {
                    throw SyExceptionUtils.e("套料异常，零件计划{},绑定ID{} 推送{}个，已套{}，待套{}，数量超了", nestSpacePart.getPartPlanId(), nestSpacePart.getId(), nestSpacePart.getTotalCount(), nestSpacePart.getFinishCount(), sum);
                }
                nestSpacePartMapper.lambdaUpdate()
                        .eq(NestSpacePart::getId, nestSpacePart.getId())
                        .set(NestSpacePart::getStatus, nestSpacePart.getStatus())
                        .set(NestSpacePart::getFinishCount, nestSpacePart.getFinishCount())
                        .set(NestSpacePart::getModifyDateTime, LocalDateTime.now())
                        .update();
            }

        }

        if (StringUtils.hasText(nest.getJobRef())) {
            nestSpacePlateMapper.lambdaUpdate()
                    .eq(NestSpacePlate::getSpaceId, nestSpace.getId())
                    .in(NestSpacePlate::getPlateCode, plates.stream().map(NestReceivePlate::getPlateCode).collect(Collectors.toList()))
                    .set(NestSpacePlate::getStatus, 4)
                    .set(NestSpacePlate::getCount, 1)
                    .set(NestSpacePlate::getModifyDateTime, LocalDateTime.now())
                    .update();
        }

    }

    public String getSplitCode(String optionId) {

        Map<String, String> params = new HashMap<>();
        params.put("1-1_HYQG_00", "HG");
        params.put("1-2_JGQG_00", "JG");
        params.put("1-3_JGQG_00", "JG");

        String groupCode = params.get(optionId);
        if (groupCode == null) {
            throw SyExceptionUtils.e("未知的切割工作组：{}", optionId);
        }

        return groupCode;
    }

    public void makeLingliao(String materCode, PlatePhase llPhase) {
        Plate plate = plateMapper.lambdaQuery().eq(Plate::getMaterCode, materCode).one();
        NestReceivePlate nestPlate = nestReceivePlateMapper.lambdaQuery().eq(NestReceivePlate::getPlateCode, materCode).one();
        List<NestReceivePart> nestParts = nestReceivePartMapper.lambdaQuery().eq(NestReceivePart::getPlateCode, materCode).list();
        List<ApsWorkDetail> apsWorkDetails = apsWorkDetailMapper.selectBatchIds(nestParts.stream().map(NestReceivePart::getPlanId).distinct().collect(Collectors.toList()));
        List<Integer> orderIds = apsWorkDetails.stream().map(ApsWorkDetail::getOrderId).distinct().collect(Collectors.toList());
        WorkDetailTask plateTask = new WorkDetailTask();
        plateTask.setMaterCode(plate.getMaterCode());
        plateTask.setMaterName(plate.getMaterName());
        plateTask.setPhaseCode(llPhase.getPhaseCode());
        plateTask.setPhaseName(llPhase.getPhaseName());
        plateTask.setGroupCode(llPhase.getGroupCode());
        plateTask.setStationCode(WorkshopProp.LL_STATION_FIRST);
        plateTask.setStatus(2);
        plateTask.setType(1);
        plateTask.setPlanStartDateTime(plate.getNestDateTime());
        plateTask.setPlanEndDateTime(plateTask.getPlanStartDateTime().plusHours(2));
        if (!CollectionUtils.isEmpty(orderIds)) {
            List<Order> orders = orderMapper.selectBatchIds(orderIds);
            plateTask.setOrderCode(orders.stream().map(Order::getConstructNo).distinct().collect(Collectors.joining(",")));
        }
        plateTask.setNorm(plate.getNorm());
        plateTask.setTexture(plate.getTexture());
        plateTask.setWeight(plate.getNestWeight());
        plateTask.setNestPlateId(nestPlate.getId());
        plateTask.setNestId(plate.getNestId());

        plateTask.setPlmid(plate.getMaterCode());
        plateTask.setTotalCount(1);
        plateTask.setNextGroupCode(WorkshopProp.YC_GROUP);
        plateTask.setNextPhaseCode(WorkshopProp.YC_PHASE_CODE);
        plateTask.setPlateCode(plate.getMaterCode());
        plateTask.setLength(plate.getLength());
        plateTask.setWidth(plate.getWidth());
        plateTask.setThickness(BigDecimal.valueOf(Integer.parseInt(plate.getNorm())));
        workDetailTaskMapper.insert(plateTask);
    }

}
